/*
 * StairLight -- Create a multi-colored Stairlight 
 *               with multiple BlinkM Devices
 *
 *  There are XX BlinkMs are addressed from 10..(10 + XX).
 *
 *  Arduino analog input 5 - I2C SCL
 *  Arduino analog input 4 - I2C SDA
 *
 * 2012 Frank Herrmann xpix.de
 *
 */

#include "Wire.h"
#include "BlinkM_funcs.h"
#include "stdarg.h";

const int num_blinkms = 12;            // Count of BlinkM's
const int blinkm_start_addr = 10;      // First BlinkM Address

const int psr_sensor_bottom_addr = 5;  // Address from Bottom Sensor
const int psr_sensor_top_addr = 25;    // Address from Top Sensor 

const unsigned long onTime = 25000;    // Timeout to switch off in milliseconds
const int SensorThreshold = 50;        // Threshold for Felix (my Cat ;)
const int LEDDelay = 250;              // Delay in ms between LED to switch on/off

char onstair               = 'i';      // State, i = idle; t = top; b = bottom;
unsigned long start        = 0;
unsigned int Wert          = 0;
unsigned int bottom_value  = 0;
unsigned int top_value     = 0;


// standard color is red
int standardColor = 0;

// color list for standardColor
byte color_list[][3] = {
  { 0xff, 0x00, 0x00 }, // red
  { 0xff, 0xff, 0xff }, // white
  { 0xff, 0x00, 0xff }, // purple
  { 0xff, 0xff, 0x00 }, // orange
  { 0x00, 0xff, 0xff }, // cyan
};
byte r,g,b; 

// Standard debug output
void debug(char *fmt, ... ){
        char tmp[128]; // resulting string limited to 128 chars
        va_list args;
        va_start (args, fmt );
        vsnprintf(tmp, 128, fmt, args);
        va_end (args);
        Serial.print(tmp);
}
  
void setup()
{
   Wire.begin();          // Init the I2C Connection
   Serial.begin(19200);   // Only for debugging

   BlinkM_begin();

   debug("Scanning I2C bus from 1-100:");
   BlinkM_scanI2CBus(1,100, scanfunc);
   debug("\n");

   // set all BlinkMs to known state
   BlinkM_stopScript( 0 );
   BlinkM_setFadeSpeed( 0, 15);
   BlinkM_fadeToRGB( 0, 0,0,0); // fade to black

   delay(1000);
   debug("Stairlight ready\n");
}

void loop()
{
   bottom_value  = ReadSensor(psr_sensor_bottom_addr);
   top_value     = ReadSensor(psr_sensor_top_addr);
   
   // First polling the sensors Bottom and top
   if(bottom_value > SensorThreshold){ // Bottom is active!!!
      debug("Bottom PSR Sensor: %d value: %d\n", psr_sensor_bottom_addr, bottom_value);
      if (onstair == 'i'){
         turnOn(1);              // from bottom to top
         onstair = 'b';
      }
      if(onstair == 't') {     // top stage was active
         turnOff(-1);            // from top to bottom
         onstair = 'i';
      }
   } 
   // ... top sensor
   if(top_value > SensorThreshold){ // Top is active!!!
      debug("Top PSR Sensor: %d value: %d\n", psr_sensor_top_addr, top_value);
      if (onstair == 'i'){
         turnOn(-1);             // from top to bottom
         onstair = 't';
      } 
      if(onstair == 'b') {     // bottom stage was active
         turnOff(1);             // from bottom to top
         onstair = 'i';
      }
   }

   // Switch off after x seconds
   if(start > 0 && millis() > (start + onTime)){
      (onstair == 'b' ? turnOff(1) : turnOff(-1));
      onstair = 'i';
   }
}

// Method to switch ON LED's as cascade 
// direct = forward (+1) or backward (-1)
void turnOn(int direct){ 

   // which standardColor?
   r = color_list[standardColor][0];
   g = color_list[standardColor][1];
   b = color_list[standardColor][2];

   // Stop all Actions on BlinkM's
   BlinkM_stopScript( 0 );

   // start time
   start = millis();

   // LEDs switch on one to one forward
   if(direct > 0){
      for (int i=0; i<=num_blinkms; i++){
        int address = blinkm_start_addr + i;
        debug("BlinkM %d switch ON!\n", address);
        if(address > 0){
            BlinkM_fadeToRGB(address, r, g, b );
        }
        my_delay(LEDDelay);
      }
   } 
   // LEDs switch on one to one backward
   else {
      for (int i=num_blinkms; i>=0; i--){
        int address = blinkm_start_addr + i;
        debug("BlinkM %d switch ON!\n", address);
        if(address > 0){
            BlinkM_fadeToRGB(address, r, g, b );
        }
        my_delay(LEDDelay);
      }
   }
}

// Method to switch OFF LED's as cascade 
// direct = forward (+1) or backward (-1)
void turnOff(int direct){
   // starttime to 0
   start = 0;

   // Stop all Actions on BlinkM's
   BlinkM_stopScript( 0 );

   // LEDs switch OFF one to one forward
   if(direct > 0){
      for (int i=0; i<=num_blinkms; i++){
        int address = blinkm_start_addr + i;
debug("BlinkM %d switch OFF!\n", address);
        if(address > 0){
            BlinkM_fadeToRGB(address, 0, 0, 0 );
        }
        my_delay(LEDDelay);
      }
   } 
   // LEDs switch OFF one to one backward
   else {
      for (int i=num_blinkms; i>=0; i--){
        int address = blinkm_start_addr + i;
debug("BlinkM %d switch OFF!\n", address);
        if(address > 0){
            BlinkM_fadeToRGB(address, 0, 0, 0 );
        }
        my_delay(LEDDelay);
      }
   }
}

// method to wait and read sensor data cuz 
// values wait in buffer and must to read ;( ???
void my_delay(unsigned long milliseconds){
   unsigned long targetTime = millis() + milliseconds;
   while (millis() < targetTime){
      ReadSensor(psr_sensor_bottom_addr);
      ReadSensor(psr_sensor_top_addr);
   }
}

// method to read sensor at address
int ReadSensor(int sensoraddr){
   Wire.beginTransmission(sensoraddr); //send Sensor to wake up
   Wire.write(1); //some value to wake up
   Wire.endTransmission();

   delay(5); //Slave need some time to get data

   Wire.requestFrom(sensoraddr, 1); //get High und Low Byte
   if (Wire.available()) { // Byte
      Wert = Wire.read();
   }
   return Wert;
}

// called when address is found in BlinkM_scanI2CBus()
void scanfunc( byte addr, byte result ) {
   Serial.print("addr: ");
   Serial.print(addr,DEC);
   Serial.print( (result==0) ? " found!":"       ");
   Serial.print( (addr%4) ? "\t":"\n");
}

